﻿using Furion;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using LS.Nc6.Core;
using System.Text.Json;
using System.Text.Encodings.Web;
using System.Text.Json.Serialization;
using System.Text.Unicode;
using LS.Nc6.Application;
using Furion.Logging;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using Furion.Templates;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Http;
using LS.Nc6.Core.Util.Extension;
using Microsoft.Extensions.FileProviders;
using System.IO;
using Microsoft.Extensions.WebEncoders;

namespace LS.Nc6.Web.Core
{
    public class Startup : AppStartup
    {
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddConfigurableOptions<JWTSettingsOptions>();
            services.AddConfigurableOptions<SystemSettingsOptions>();
            services.AddJwt<JwtHandler>(options =>
            {
                options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
                options.DefaultChallengeScheme = CookieAuthenticationDefaults.AuthenticationScheme;
            }).AddCookie(CookieAuthenticationDefaults.AuthenticationScheme, options =>
            {
                options.LoginPath = "/Login";
            }); 
          

            services.AddCorsAccessor();

            services.AddControllersWithViews()
             .AddMvcFilter<RequestActionFilter>()
             .AddInjectWithUnifyResult<RestfulResultProvider>()
             .AddJsonOptions(options =>
             {
                 //options.JsonSerializerOptions.DefaultBufferSize = 10_0000;//返回较大数据数据序列化时会截断，原因：默认缓冲区大小（以字节为单位）为16384。
                 options.JsonSerializerOptions.Converters.AddDateFormatString("yyyy-MM-dd HH:mm:ss");
                 options.JsonSerializerOptions.Converters.Add(new LongJsonConverter()); // 配置过长的整数类型返回前端会丢失精度的问题
                 options.JsonSerializerOptions.Encoder = JavaScriptEncoder.Create(UnicodeRanges.All);
                 options.JsonSerializerOptions.ReferenceHandler = ReferenceHandler.IgnoreCycles; // 忽略循环引用 仅.NET 6支持
             });
           
            // 注册EventBus服务
            services.AddEventBus(builder =>
            {
                // 注册 Log 日志订阅者
                builder.AddSubscriber<LogEventSubscriber>();
            });

            // 日志记录
            // 错误级别日志归类
            // 每天创建一个日志文件
            services.AddLogging(builder =>
            {
                builder.AddFile("logs/error/{0:yyyyMMdd}_.log", options =>
                {
                    SetLogOptions(options, LogLevel.Error);
                });
                builder.AddFile("logs/info/{0:yyyyMMdd}_.log", options =>
                {
                    SetLogOptions(options, LogLevel.Information);
                });
                builder.AddFile("logs/warn/{0:yyyyMMdd}_.log", options =>
                {
                    SetLogOptions(options, LogLevel.Warning);
                });
            });

            //添加 身份验证 服务
            //services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme).
            //AddCookie(CookieAuthenticationDefaults.AuthenticationScheme, o =>
            //{
            //    o.LoginPath = new PathString("/Login");// 登录页面的url
            //    o.AccessDeniedPath = new PathString("/Login");//没有授权跳转的页面
            //    o.ExpireTimeSpan = TimeSpan.FromHours(0.5); // cookies的过期时间
            //});

            //默认使用内存存储（AddDistributedMemoryCache）
            services.AddCaptcha(App.Configuration);

            // 如果使用redis分布式缓存
            //builder.Services.AddStackExchangeRedisCache(options =>
            //{
            //    options.Configuration = builder.Configuration.GetConnectionString("RedisCache");
            //    options.InstanceName = "captcha:";
            //});

            services.Configure<WebEncoderOptions>(options =>
            {
                options.TextEncoderSettings = new TextEncoderSettings(UnicodeRanges.All);
            });
            services.AddComponent<TextSerchServiceComponent>();
        }

        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseExceptionHandler("/Home/Error");
                app.UseHsts();
            }
            // 添加状态码拦截中间件
            app.UseUnifyResultStatusCodes();

            //app.UseHttpsRedirection();
            app.UseStaticFiles();
            app.UseStaticFiles(new StaticFileOptions()  {
                FileProvider = new PhysicalFileProvider(
                Path.Combine(Directory.GetCurrentDirectory(), @"Upload")),
                RequestPath = new PathString("/Upload")
            });

            app.UseRouting();

            app.UseCorsAccessor();

            app.UseAuthentication();
            app.UseAuthorization();

            app.UseInject();

            app.UseStaticHostEnviroment();

            app.UseEndpoints(endpoints =>
            {
              
                endpoints.MapControllerRoute(
                    name: "default",
                    pattern: "{controller=Login}/{action=Index}/{id?}");


                //区域路由配置
                endpoints.MapAreaControllerRoute(
                                    name: "areas", "areas",
                                 pattern: "{area:exists}/{controller=Home}/{action=Index}/{id?}");

            });
          
        }

        private void SetLogOptions(FileLoggerOptions options, LogLevel logLevel)
        {
            options.WriteFilter = (logMsg) =>
            {
                return logMsg.LogLevel == logLevel;
            };
            options.FileNameRule = fileName =>
            {
                return string.Format(fileName, DateTime.UtcNow);
            };
            options.FileSizeLimitBytes = 500 * 1024;
            options.MessageFormat = (logMsg) =>
            {
                List<string> msg = new List<string>() {
                $"##日志时间## {DateTime.Now.ToString("O")}",
                $"##日志等级## {logLevel}",
                $"##日志内容## {logMsg.Message}",
            };
                if (!string.IsNullOrEmpty(logMsg.Exception?.ToString())) msg.Add($"##异常信息## {logMsg.Exception}");

                // 生成模板字符串
                var template = TP.Wrapper($"{logMsg.LogName}", "", msg.ToArray());
                return template;
            };
        }
    }
}